package main

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"time"
)

// PredictionCurve 预测曲线数据结构
type PredictionCurve struct {
	ID        string    `json:"id"`         // 唯一标识
	Date      string    `json:"date"`       // 日期 (YYYY-MM-DD)
	CreatedAt time.Time `json:"created_at"` // 创建时间
	UpdatedAt time.Time `json:"updated_at"` // 更新时间
	Version   int       `json:"version"`    // 版本号

	// 预测数据
	Prediction30min     []float64 `json:"prediction_30min"`       // 30分钟预测 (48个值，0-24小时)
	Prediction3h        []float64 `json:"prediction_3h"`          // 3小时预测 (8个值，0-24小时)
	NextDayPrediction3h []float64 `json:"next_day_prediction_3h"` // 次日预测 (2个值，0-6小时)

	// 元数据
	UpdateReason   string `json:"update_reason"`   // 更新原因
	UpdateScenario string `json:"update_scenario"` // 更新场景
	UpdateRange    string `json:"update_range"`    // 更新范围
}

// PredictionStorage 预测曲线存储管理器
type PredictionStorage struct {
	baseDir string // 存储根目录
}

// NewPredictionStorage 创建存储管理器
func NewPredictionStorage(baseDir string) (*PredictionStorage, error) {
	// 确保目录存在
	if err := os.MkdirAll(baseDir, 0755); err != nil {
		return nil, fmt.Errorf("failed to create storage directory: %w", err)
	}

	return &PredictionStorage{
		baseDir: baseDir,
	}, nil
}

// SavePrediction 保存预测曲线
func (ps *PredictionStorage) SavePrediction(curve *PredictionCurve) error {
	// 更新时间戳
	curve.UpdatedAt = time.Now()
	if curve.CreatedAt.IsZero() {
		curve.CreatedAt = curve.UpdatedAt
	}

	// 生成文件路径：baseDir/YYYY-MM-DD/prediction_vN.json
	dateDir := filepath.Join(ps.baseDir, curve.Date)
	if err := os.MkdirAll(dateDir, 0755); err != nil {
		return fmt.Errorf("failed to create date directory: %w", err)
	}

	filename := fmt.Sprintf("prediction_v%d.json", curve.Version)
	targetFilePath := filepath.Join(dateDir, filename)

	// 序列化为JSON
	data, err := json.MarshalIndent(curve, "", "  ")
	if err != nil {
		return fmt.Errorf("failed to marshal prediction: %w", err)
	}

	// 写入文件
	if err := os.WriteFile(targetFilePath, data, 0644); err != nil {
		return fmt.Errorf("failed to write prediction file: %w", err)
	}

	// 同时保存为 latest.json（方便快速读取最新版本）
	latestPath := filepath.Join(dateDir, "latest.json")
	if err := os.WriteFile(latestPath, data, 0644); err != nil {
		return fmt.Errorf("failed to write latest prediction: %w", err)
	}

	logMessage(LogLevelInfo, "✓ Saved prediction curve: %s (version %d)\n", targetFilePath, curve.Version)
	return nil
}

// LoadLatestPrediction 加载最新的预测曲线
func (ps *PredictionStorage) LoadLatestPrediction(date string) (*PredictionCurve, error) {
	dateDir := filepath.Join(ps.baseDir, date)
	latestPath := filepath.Join(dateDir, "latest.json")

	data, err := os.ReadFile(latestPath)
	if err != nil {
		return nil, fmt.Errorf("failed to read latest prediction: %w", err)
	}

	var curve PredictionCurve
	if err := json.Unmarshal(data, &curve); err != nil {
		return nil, fmt.Errorf("failed to unmarshal prediction: %w", err)
	}

	return &curve, nil
}

// LoadPredictionByVersion 加载指定版本的预测曲线
func (ps *PredictionStorage) LoadPredictionByVersion(date string, version int) (*PredictionCurve, error) {
	dateDir := filepath.Join(ps.baseDir, date)
	filename := fmt.Sprintf("prediction_v%d.json", version)
	filepath := filepath.Join(dateDir, filename)

	data, err := os.ReadFile(filepath)
	if err != nil {
		return nil, fmt.Errorf("failed to read prediction version %d: %w", version, err)
	}

	var curve PredictionCurve
	if err := json.Unmarshal(data, &curve); err != nil {
		return nil, fmt.Errorf("failed to unmarshal prediction: %w", err)
	}

	return &curve, nil
}

// ListVersions 列出某日期的所有版本
func (ps *PredictionStorage) ListVersions(date string) ([]int, error) {
	dateDir := filepath.Join(ps.baseDir, date)

	entries, err := os.ReadDir(dateDir)
	if err != nil {
		if os.IsNotExist(err) {
			return []int{}, nil
		}
		return nil, fmt.Errorf("failed to read date directory: %w", err)
	}

	versions := []int{}
	for _, entry := range entries {
		if entry.IsDir() {
			continue
		}

		var version int
		if _, err := fmt.Sscanf(entry.Name(), "prediction_v%d.json", &version); err == nil {
			versions = append(versions, version)
		}
	}

	return versions, nil
}

// CreateInitialPrediction 创建初始预测曲线
func CreateInitialPrediction(date string, pred30min, pred3h, nextDay3h []float64) *PredictionCurve {
	return &PredictionCurve{
		ID:                  generateID(),
		Date:                date,
		CreatedAt:           time.Now(),
		UpdatedAt:           time.Now(),
		Version:             1,
		Prediction30min:     pred30min,
		Prediction3h:        pred3h,
		NextDayPrediction3h: nextDay3h,
		UpdateReason:        "初始化",
		UpdateScenario:      "初始化",
		UpdateRange:         "全天",
	}
}

// generateID 生成唯一ID
func generateID() string {
	return fmt.Sprintf("%d", time.Now().UnixNano())
}

// PrintPredictionCurve 打印预测曲线信息
func PrintPredictionCurve(curve *PredictionCurve) {
	logTitle(LogLevelInfo, "预测曲线信息")

	logMessage(LogLevelInfo, "ID:           %s\n", curve.ID)
	logMessage(LogLevelInfo, "日期:         %s\n", curve.Date)
	logMessage(LogLevelInfo, "版本:         v%d\n", curve.Version)
	logMessage(LogLevelInfo, "创建时间:     %s\n", curve.CreatedAt.Format(TimeLayout))
	logMessage(LogLevelInfo, "更新时间:     %s\n", curve.UpdatedAt.Format(TimeLayout))
	logMessage(LogLevelInfo, "更新原因:     %s\n", curve.UpdateReason)
	logMessage(LogLevelInfo, "更新场景:     %s\n", curve.UpdateScenario)
	logMessage(LogLevelInfo, "更新范围:     %s\n", curve.UpdateRange)

	logSeparator(LogLevelInfo, "-", 60)

	// 打印3小时预测
	logMessage(LogLevelInfo, "\n3小时预测曲线 (8个值):\n")
	for i, val := range curve.Prediction3h {
		startHour := i * 3
		endHour := startHour + 3
		logMessage(LogLevelInfo, "  块%d [%02d:00-%02d:00]: %.2f m³\n", i, startHour, endHour, val)
	}

	// 打印30分钟预测（每3小时汇总）
	logMessage(LogLevelInfo, "\n30分钟预测曲线 (48个值，按3小时汇总):\n")
	for i := 0; i < 8; i++ {
		startIdx := i * 6
		endIdx := startIdx + 6
		if endIdx > len(curve.Prediction30min) {
			endIdx = len(curve.Prediction30min)
		}

		sum := 0.0
		for j := startIdx; j < endIdx; j++ {
			sum += curve.Prediction30min[j]
		}

		startHour := i * 3
		endHour := startHour + 3
		logMessage(LogLevelInfo, "  块%d [%02d:00-%02d:00]: %.2f m³ (6个30分钟值之和)\n",
			i, startHour, endHour, sum)
	}

	// 打印次日预测
	if len(curve.NextDayPrediction3h) > 0 {
		logMessage(LogLevelInfo, "\n次日预测 (前%d个3小时块):\n", len(curve.NextDayPrediction3h))
		for i, val := range curve.NextDayPrediction3h {
			startHour := i * 3
			endHour := startHour + 3
			logMessage(LogLevelInfo, "  块%d [%02d:00-%02d:00]: %.2f m³\n", i, startHour, endHour, val)
		}
	}

	logSeparator(LogLevelInfo, "=", 60)
}
